From 562ae5e647cf9bfaaeba5c13e8e9ec2cf04fbdc7 Mon Sep 17 00:00:00 2001 From: tsteven4 Date: Sat, 24 Aug 2013 01:51:54 +0000 Subject: [PATCH] checkpoint new gpx reader based on QXmlStreamReader instead of expat. the new gpx reader is disabled. --- gpsbabel/gpx.cc | 268 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 264 insertions(+), 4 deletions(-) diff --git a/gpsbabel/gpx.cc b/gpsbabel/gpx.cc index b9aa5818b..129c78ca3 100644 --- a/gpsbabel/gpx.cc +++ b/gpsbabel/gpx.cc @@ -23,9 +23,12 @@ #include "cet_util.h" #include "garmin_fs.h" #include -#if HAVE_LIBEXPAT +#if HAVE_LIBEXPAT && !defined(NEW_GPX_READER) #include static XML_Parser psr; +#else +#include +static QXmlStreamReader* reader; #endif #include "src/core/file.h" #include "src/core/xmlstreamwriter.h" @@ -52,7 +55,11 @@ static QString current_tag; static waypoint* wpt_tmp; static UrlLink* link_; static int cache_descr_is_html; +#ifndef NEW_GPX_READER static gbfile* fd; +#else +static gpsbabel::File* iqfile; +#endif static gpsbabel::File* oqfile; static gpsbabel::XmlStreamWriter* writer; static short_handle mkshort_handle; @@ -459,6 +466,7 @@ prescan_tags(void) } } +#ifndef NEW_GPX_READER static void tag_gpx(const char** attrv) { @@ -485,7 +493,43 @@ tag_gpx(const char** attrv) } } } +#else +static void +tag_gpx(const QXmlStreamAttributes& attr) +{ + if (attr.hasAttribute("version")) { + /* Set the default output version to the highest input + * version. + */ + if (! gpx_version) { + gpx_version = xstrdup(CSTR(attr.value("version").toString())); + } else if ((strtod(gpx_version, NULL) * 10) < (attr.value("version").toString().toDouble() * 10)) { + xfree(gpx_version); + gpx_version = xstrdup(CSTR(attr.value("version").toString())); + } + } + if (attr.hasAttribute("src")) { + /* TODO: this is unused */ + /* FIXME: this data may be deallocated */ + gpx_creator = CSTR(attr.value("src").toString()); + } + /* save namespace declarations in case we pass through elements + * that use them to the writer. + */ + const QXmlStreamNamespaceDeclarations ns = reader->namespaceDeclarations(); + for (int i = 0; i < ns.size(); ++i) { + QString prefix = ns[i].prefix().toString(); + QString namespaceUri = ns[i].namespaceUri().toString(); + if (!prefix.isEmpty() && (0 != prefix.compare("xsi"))) { + if (! gpx_namespace_attribute.hasAttribute(prefix)) { + gpx_namespace_attribute.append(prefix.prepend("xmlns:"), namespaceUri); + } + } + } +} +#endif +#ifndef NEW_GPX_READER static void tag_wpt(const char** attrv) { @@ -507,7 +551,25 @@ tag_wpt(const char** attrv) } fs_ptr = &wpt_tmp->fs; } +#else +static void +tag_wpt(const QXmlStreamAttributes& attr) +{ + wpt_tmp = waypt_new(); + link_ = new UrlLink; + + cur_tag = NULL; + if (attr.hasAttribute("lat")) { + wpt_tmp->latitude = attr.value("lat").toString().toDouble(); + } + if (attr.hasAttribute("lon")) { + wpt_tmp->longitude = attr.value("lon").toString().toDouble(); + } + fs_ptr = &wpt_tmp->fs; +} +#endif +#ifndef NEW_GPX_READER static void tag_cache_desc(const char** attrv) { @@ -522,7 +584,20 @@ tag_cache_desc(const char** attrv) } } } +#else +static void +tag_cache_desc(const QXmlStreamAttributes& attr) +{ + cache_descr_is_html = 0; + if (attr.hasAttribute("html")) { + if (attr.value("html").toString().compare("True") == 0) { + cache_descr_is_html = 1; + } + } +} +#endif +#ifndef NEW_GPX_READER static void tag_gs_cache(const char** attrv) { @@ -547,8 +622,34 @@ tag_gs_cache(const char** attrv) } } } +#else +static void +tag_gs_cache(const QXmlStreamAttributes& attr) +{ + geocache_data* gc_data = waypt_alloc_gc_data(wpt_tmp); + + if (attr.hasAttribute("id")) { + gc_data->id = attr.value("id").toString().toInt(); + } + if (attr.hasAttribute("available")) { + if (attr.value("available").toString().compare("True", Qt::CaseInsensitive) == 0) { + gc_data->is_available = status_true; + } else if (attr.value("available").toString().compare("False", Qt::CaseInsensitive) == 0) { + gc_data->is_available = status_false; + } + } + if (attr.hasAttribute("archived")) { + if (attr.value("archived").toString().compare("True", Qt::CaseInsensitive) == 0) { + gc_data->is_archived = status_true; + } else if (attr.value("archived").toString().compare("False", Qt::CaseInsensitive) == 0) { + gc_data->is_archived = status_false; + } + } +} +#endif static void +#ifndef NEW_GPX_READER start_something_else(const char* el, const char** attrv) { const char** avp = attrv; @@ -580,6 +681,32 @@ start_something_else(const char* el, const char** attrv) avp++; } *avcp = NULL; +#else +start_something_else(const QString el, const QXmlStreamAttributes& attr) +{ + char** avcp; + int attr_count; + xml_tag* new_tag; + fs_xml* fs_gpx; + + if (!fs_ptr) { + return; + } + + new_tag = (xml_tag*)xcalloc(sizeof(xml_tag),1); + new_tag->tagname = xstrdup(CSTR(el)); + + attr_count = attr.size(); + new_tag->attributes = (char**)xcalloc(sizeof(char*),2*attr_count+1); + avcp = new_tag->attributes; + for (int i = 0; i < attr_count; i++) { + *avcp = xstrdup(CSTR(attr[i].name().toString())); + avcp++; + *avcp = xstrdup(CSTR(attr[i].value().toString())); + avcp++; + } + *avcp = NULL; // this indicates the end of the attribute name value pairs. +#endif if (cur_tag) { if (cur_tag->child) { @@ -621,6 +748,7 @@ end_something_else() } } +#ifndef NEW_GPX_READER static void tag_log_wpt(const char** attrv) { @@ -657,16 +785,53 @@ tag_log_wpt(const char** attrv) waypt_add(lwp_tmp); } } +#else +static void +tag_log_wpt(const QXmlStreamAttributes& attr) +{ + /* create a new waypoint */ + waypoint* lwp_tmp = waypt_new(); + + /* extract the lat/lon attributes */ + if (attr.hasAttribute("lat")) { + lwp_tmp->latitude = attr.value("lat").toString().toDouble(); + } + if (attr.hasAttribute("lon")) { + lwp_tmp->longitude = attr.value("lon").toString().toDouble(); + } + /* Make a new shortname. Since this is a groundspeak extension, + we assume that GCBLAH is the current shortname format and that + wpt_tmp refers to the currently parsed waypoint. Unfortunatley, + we need to keep track of log_wpt counts so we don't collide with + dupe shortnames. + */ + + if ((wpt_tmp->shortname) && (strlen(wpt_tmp->shortname) > 2)) { + /* copy of the shortname */ + lwp_tmp->shortname = (char*) xcalloc(7, 1); + sprintf(lwp_tmp->shortname, "%-4.4s%02d", + &wpt_tmp->shortname[2], logpoint_ct++); + + waypt_add(lwp_tmp); + } +} +#endif static void +#ifndef NEW_GPX_READER gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr) +#else +gpx_start(const QString& el, const QXmlStreamAttributes& attr) +#endif { int passthrough; int tag; +#ifndef NEW_GPX_READER const char* el = xml_convert_to_char_string(xml_el); const char** attr = xml_convert_attrs_to_char_string(xml_attr); current_tag.append("/"); current_tag.append(el); +#endif /* @@ -683,9 +848,15 @@ gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr) tag_wpt(attr); break; case tt_wpt_link: +#ifndef NEW_GPX_READER if (attr[0] && attr[1] && 0 == strcmp(attr[0], "href")) { link_url = xstrdup(attr[1]); } +#else + if (attr.hasAttribute("href")) { + link_url = xstrdup(CSTR(attr.value("href").toString())); + } +#endif break; case tt_rte: rte_head = route_head_alloc(); @@ -723,17 +894,25 @@ gpx_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr) tag_cache_desc(attr); break; case tt_cache_placer: +#ifndef NEW_GPX_READER if (*attr && (0 == strcmp(attr[0], "id"))) { waypt_alloc_gc_data(wpt_tmp)->placer_id = atoi(attr[1]); } +#else + if (attr.hasAttribute("id")) { + waypt_alloc_gc_data(wpt_tmp)->placer_id = attr.value("id").toString().toInt(); + } +#endif default: break; } if (passthrough) { start_something_else(el, attr); } +#ifndef NEW_GPX_READER xml_free_converted_string(el); xml_free_converted_attrs(attr); +#endif } struct @@ -906,9 +1085,15 @@ xml_parse_time(const QString& dateTimeString) } static void +#ifndef NEW_GPX_READER gpx_end(void* data, const XML_Char* xml_el) +#else +gpx_end(const QString& el) +#endif { +#ifndef NEW_GPX_READER const char* el = xml_convert_to_char_string(xml_el); +#endif int pos = current_tag.lastIndexOf('/'); QString s = current_tag.mid(pos + 1); float x; @@ -918,7 +1103,12 @@ gpx_end(void* data, const XML_Char* xml_el) tag_type tag; if (s.compare(el)) { +#ifndef NEW_GPX_READER fprintf(stderr, "Mismatched tag %s. Expected %s\n", el, qPrintable(s)); +#else +// TODO: I don't think this is necesary with QXmlStreamReader + fprintf(stderr, "Mismatched tag %s. Expected %s\n", CSTR(el), qPrintable(s)); +#endif } tag = get_tag(current_tag, &passthrough); @@ -1216,7 +1406,9 @@ gpx_end(void* data, const XML_Char* xml_el) break; case tt_unknown: end_something_else(); +#ifndef NEW_GPX_READER current_tag.truncate(pos); +#endif return; default: break; @@ -1226,11 +1418,13 @@ gpx_end(void* data, const XML_Char* xml_el) end_something_else(); } +#ifndef NEW_GPX_READER current_tag.truncate(pos); xml_free_converted_string(el); +#endif } -#if ! HAVE_LIBEXPAT +#if ! HAVE_LIBEXPAT && !defined(NEW_GPX_READER) static void gpx_rd_init(const char* fname) { @@ -1245,14 +1439,22 @@ gpx_rd_deinit(void) #else /* NO_EXPAT */ static void +#ifndef NEW_GPX_READER gpx_cdata(void* dta, const XML_Char* xml_el, int len) +#else +gpx_cdata(const char* s) +#endif { char* estr; int* cdatalen; char** cdata; xml_tag* tmp_tag; size_t slen = strlen(cdatastr.mem); +#ifndef NEW_GPX_READER const char* s = xml_convert_to_char_string_n(xml_el, &len); +#else + int len = strlen(s); +#endif vmem_realloc(&cdatastr, 1 + len + slen); estr = ((char*) cdatastr.mem) + slen; @@ -1281,23 +1483,33 @@ gpx_cdata(void* dta, const XML_Char* xml_el, int len) *(estr+len) = '\0'; *cdatalen += len; +#ifndef NEW_GPX_READER xml_free_converted_string(s); +#endif } static void gpx_rd_init(const char* fname) { +#ifndef NEW_GPX_READER fd = gbfopen(fname, "r", MYNAME); +#else + iqfile = new gpsbabel::File(fname); + iqfile->open(QIODevice::ReadOnly); + reader = new QXmlStreamReader(iqfile); +#endif current_tag.clear(); prescan_tags(); +#ifndef NEW_GPX_READER psr = XML_ParserCreate(NULL); if (!psr) { fatal(MYNAME ": Cannot create XML Parser\n"); } XML_SetUnknownEncodingHandler(psr, cet_lib_expat_UnknownEncodingHandler, NULL); +#endif cdatastr = vmem_alloc(1, 0); *((char*)cdatastr.mem) = '\0'; @@ -1313,8 +1525,10 @@ gpx_rd_init(const char* fname) QUEUE_INIT(&gpx_global->keywords.queue); } +#ifndef NEW_GPX_READER XML_SetElementHandler(psr, gpx_start, gpx_end); XML_SetCharacterDataHandler(psr, gpx_cdata); +#endif fs_ptr = NULL; } @@ -1324,11 +1538,19 @@ gpx_rd_deinit(void) { vmem_free(&cdatastr); +#ifndef NEW_GPX_READER if (fd) { gbfclose(fd); } XML_ParserFree(psr); psr = NULL; +#else + delete reader; + reader = NULL; + iqfile->close(); + delete iqfile; + iqfile = NULL; +#endif wpt_tmp = NULL; cur_tag = NULL; } @@ -1363,7 +1585,7 @@ gpx_wr_deinit(void) void gpx_read(void) { -#if HAVE_LIBEXPAT +#if HAVE_LIBEXPAT && !defined(NEW_GPX_READER) int len; char* buf = (char*) xmalloc(MY_CBUF_SZ); @@ -1375,7 +1597,45 @@ gpx_read(void) } } xfree(buf); -#endif /* HAVE_LIBEXPAT */ +#else + while (!reader->atEnd()) { + reader->readNext(); + // do processing + switch (reader->tokenType()) { + case QXmlStreamReader::StartElement: + current_tag.append("/"); + current_tag.append(reader->qualifiedName()); + + { + const QXmlStreamAttributes attrs = reader->attributes(); + gpx_start(reader->qualifiedName().toString(), attrs); + } + break; + + case QXmlStreamReader::EndElement: + gpx_end(reader->qualifiedName().toString()); + current_tag.chop(reader->qualifiedName().length() + 1); + break; + + case QXmlStreamReader::Characters: +// It is tempting to skip this if reader->isWhitespace(). +// That would lose all whitespace element values if the exist, +// but it would skip line endings and indentation that doesn't matter. + gpx_cdata(CSTR(reader->text().toString())); + break; + + default: + break; + } + } + if (reader->hasError()) { + fatal(MYNAME ":Read error: %s (%s, line %ld, col %ld)\n", + CSTR(reader->errorString()), + CSTR(iqfile->fileName()), + (long) reader->lineNumber(), + (long) reader->columnNumber()); + } +#endif /* USE_LIBEXPAT */ } static void -- 2.30.2